#ifndef __wqueue_h__
#define __wqueue_h__
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "thread.h"
#include "Moderador.h"
#include "Login.h"
#include <pthread.h>
#include "../Common/Conexion.h"
#include <vector>
#include "NodoAdmin.h"
#include "HiloModelo.h"



class Moderador {
	int ultimoIdAdmin;
	int ultimoIdCliente;
	pthread_mutex_t m_mutex;
	pthread_cond_t m_condv;
	std::vector<NodoAdmin> vecAdmin;

public:
	Moderador() {
		ultimoIdAdmin = 0;
		ultimoIdCliente = 0;
		pthread_mutex_init(&m_mutex, NULL);
		pthread_cond_init(&m_condv, NULL);
	}
	~Moderador() {
		pthread_mutex_destroy(&m_mutex);
		pthread_cond_destroy(&m_condv);
	}

	int agregarCliente( Conexion* cnxCliente, int idPartida,int idCliente,int nivel, Json::Value credencial ){
		NodoCliente nodo(nivel, cnxCliente, credencial["usuario"].asString(),credencial["clave"].asString() );
		nodo.setId(idCliente);
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();it1 != vecAdmin.end(); ++it1) {
				if((*it1).getId() == idPartida)
				(*it1).getVec()->push_back(nodo);
		}
		pthread_mutex_unlock(&m_mutex);
		return idPartida;
	}

	int agregarPartida(Conexion* cnxCliente, int idCliente, int nivel, int maxJugadores, Json::Value credencial){
		int idAdmin;
		NodoCliente nodo(nivel, cnxCliente, credencial["usuario"].asString(),credencial["clave"].asString() );
		nodo.setId(idCliente);
		pthread_mutex_lock(&m_mutex);
			ultimoIdAdmin++;
			NodoAdmin nuevoAdmin;
			nuevoAdmin.setId(ultimoIdAdmin);
			nuevoAdmin.setNivel(nivel);
			nuevoAdmin.setMaxPlayers(maxJugadores);
			nuevoAdmin.getVec()->push_back(nodo);
			vecAdmin.push_back(nuevoAdmin);
			idAdmin = ultimoIdAdmin;
		pthread_mutex_unlock(&m_mutex);
		return idAdmin;
	}

	void imprimirClientes() {
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
				it1 != vecAdmin.end(); ++it1) {
			for (std::vector<NodoCliente>::iterator it2 = (*it1).getVec()->begin();
					it2 != (*it1).getVec()->end(); ++it2) {
			}
		}
		pthread_mutex_unlock(&m_mutex);
	}

	bool setMensaje(int idAdmin, int idCliente, const std::string& mensaje) {
		bool seAgrego = false;
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
				it1 != vecAdmin.end(); ++it1) {
			if ((*it1).getId() == idAdmin) {
				if ((*it1).getHayDatos() == false) {
					(*it1).setMensaje(mensaje);
					(*it1).setHayDatos(true);
					(*it1).setIdClienteMensaje(idCliente);
				}
			}
		}
		pthread_mutex_unlock(&m_mutex);
		return seAgrego;
	}



	void enviarMensaje(const std::string& mensaje, int idAdmin) {
		std::cout << mensaje << std::endl;
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
				it1 != vecAdmin.end(); ++it1) {
			if ((*it1).getId() == idAdmin) {
				for (std::vector<NodoCliente>::iterator it2 =
						(*it1).getVec()->begin();
							it2 != (*it1).getVec()->end(); ++it2){
					(*it2).enviar(mensaje);
				}
				pthread_mutex_unlock(&m_mutex);
				break;
			}
		}
	}

	void enviarMensajeParticular(const std::string& mensaje, int idAdmin,
												int idCliente, int condicion){
		// si condicion es 0 manda a todos menos uno
		// si condicion es 1 manda a uno
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
											it1 != vecAdmin.end(); ++it1){
			if ((*it1).getId() == idAdmin) {
				for (std::vector<NodoCliente>::iterator it2 =
									(*it1).getVec()->begin();
									it2 != (*it1).getVec()->end(); ++it2){
					if((*it2).getId() == idCliente && condicion == 1){
						(*it2).enviar(mensaje);
					}
					if((*it2).getId() != idCliente && condicion == 0){
						(*it2).enviar(mensaje);
					}
				}
				pthread_mutex_unlock(&m_mutex);
				break;
			}
		}
	}

	std::string getKey(int idAdmin,int idCliente){
		std::string key;

		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();it1 != vecAdmin.end(); ++it1){
			if ((*it1).getId() == idAdmin) {
				for (std::vector<NodoCliente>::iterator it2 =(*it1).getVec()->begin();it2 != (*it1).getVec()->end(); ++it2){
					if((*it2).getId() == idCliente){
						pthread_mutex_unlock(&m_mutex);
						key=(*it2).getclave();
						return key;
					}
				}

			}
		}
		return "";
	}




	bool hayDatos(int idAdmin) {
		bool haydatos;
		pthread_mutex_lock(&m_mutex);
		std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
		while (it1 != vecAdmin.end() && (*it1).getId() != idAdmin) {
			++it1;
		}
		haydatos = (*it1).getHayDatos();
		pthread_mutex_unlock(&m_mutex);
		return haydatos;
	}

	int getIdClienteMensaje(int idAdmin) {
		int id;
		pthread_mutex_lock(&m_mutex);
		std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
		while (it1 != vecAdmin.end() && (*it1).getId() != idAdmin) {
			++it1;
		}
		id = (*it1).getIdClienteMensaje();
		pthread_mutex_unlock(&m_mutex);
		return id;
	}

	std::string getMensaje(int idAdmin) {
		std::string mensaje = "";
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
				it1 != vecAdmin.end(); ++it1) {
			if ((*it1).getId() == idAdmin) {
				mensaje = (*it1).getMensaje();
				(*it1).setHayDatos(false);
			}
		}
		pthread_mutex_unlock(&m_mutex);
		return mensaje;
	}

	int nuevoIdCliente() {
		int id;
		pthread_mutex_lock(&m_mutex);
		id = ultimoIdCliente++;
		pthread_mutex_unlock(&m_mutex);
		return id;
	}

	void lanzarPartidas(int nivel) {
		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
				it1 != vecAdmin.end(); ++it1) {
			if ((*it1).getVec()->size() == (unsigned int)(*it1).getMaxPlayers() && (*it1).getLanzado() == false) {
				(*it1).setModelo(new HiloModelo(this, nivel));
				(*it1).setLanzado(true);
				(*it1).getModelo()->setIdAdmin((*it1).getId());
				(*it1).getModelo()->start();
			}
		}
		pthread_mutex_unlock(&m_mutex);
	}

	std::string getUserClienteMensaje(int idAdmin) {
		std::string user;
		pthread_mutex_lock(&m_mutex);
		std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
		while (it1 != vecAdmin.end() && (*it1).getId() != idAdmin){
			++it1;
		}

		user = (*it1).getUserClienteMensaje();
		pthread_mutex_unlock(&m_mutex);
		return user;
	}

	void sumarPuntos(int puntos, int idAdmin){
		pthread_mutex_lock(&m_mutex);
		std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
		while (it1 != vecAdmin.end() && (*it1).getId() != idAdmin){
			++it1;
		}
		(*it1).sumarPuntos(puntos);
		pthread_mutex_unlock(&m_mutex);
	}

	Json::Value getVecJsonPuntajes(int idAdmin){
		Json::Value json;
		pthread_mutex_lock(&m_mutex);
		std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
		while (it1 != vecAdmin.end() && (*it1).getId() != idAdmin){
			++it1;
		}
		json = (*it1).getVecJsonPuntajes();
		pthread_mutex_unlock(&m_mutex);
		return json;
	}

	int getPuntosCliente(int idAdmin) {
		int puntos;
		pthread_mutex_lock(&m_mutex);
		std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin();
		while (it1 != vecAdmin.end() && (*it1).getId() != idAdmin){
			++it1;
		}
		puntos = (*it1).getPuntos();
		pthread_mutex_unlock(&m_mutex);
		return puntos;
	}
	
	Json::Value partidasToJson(){
		Json::Value json_book;
		Json::Value json_value;
		Json::Value vecPartidas_json(Json::arrayValue);

		pthread_mutex_lock(&m_mutex);
		for (std::vector<NodoAdmin>::iterator it1 = vecAdmin.begin(); it1 != vecAdmin.end(); ++it1) {
			if ( (*it1).getLanzado() == false) {
				json_value["id"]=(*it1).getId();
				json_value["nivel"]=(*it1).getNivel();
				json_value["maxJugadores"]=(*it1).getMaxPlayers();
				json_value["conectados"]=(int)(*it1).getVec()->size();
				vecPartidas_json.append(json_value);
			}
		}
		json_book["partidas"] = vecPartidas_json;
		pthread_mutex_unlock(&m_mutex);
		return json_book;
	}
};

#endif
